// perl_scriptrunner.cpp - script runner

#include "PlPN.h"

/*
 * PerlScriptRunner
 */

PerlScriptRunner::PerlScriptRunner(const char* classname) {
	CreatePerlObj(classname, (void*)this);
}

PerlScriptRunner::~PerlScriptRunner() {
	free((void*)m_id);
	m_id = NULL;
}

void PerlScriptRunner::RunScript(const char* name) {
	if (! m_in_use)
		return;

	dSP;

    ENTER;
    SAVETMPS;

	PUSHMARK(SP);
	XPUSHs(m_perl_obj);
	XPUSHs(sv_2mortal(newSVpv(name, 0)));	// length of 0 means Perl will calculate
	PUTBACK;
	
	call_method("RunScript", G_VOID|G_EVAL);
	SPAGAIN;

	if(SvTRUE(ERRSV)) {
		STRLEN n_a;
		alert("Error calling Perl version of RunScript: %s\n", SvPV(ERRSV,n_a));
		POPs;
	}
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return;
}

void PerlScriptRunner::RunDocScript(extensions::IDocumentPtr& doc) {
	if (! m_in_use)
		return;

	// get the doc
	TrackedDocument* tdoc = g_document_tracker.Fetch(doc);
	// if (for some reason) it's not being tracked, start tracking it
	if (tdoc == NULL)
		g_document_tracker.Add(doc, &tdoc);

	dSP;

    ENTER;
    SAVETMPS;

	PUSHMARK(SP);
	XPUSHs(m_perl_obj);
	XPUSHs(tdoc->perl_doc);
	PUTBACK;
	
	call_method("RunDocScript", G_VOID|G_EVAL);
	SPAGAIN;

	if(SvTRUE(ERRSV)) {
		STRLEN n_a;
		alert("Error calling Perl version of RunDocScript: %s\n", SvPV(ERRSV,n_a));
		POPs;
	}
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return;
}

void PerlScriptRunner::Eval(const char* script, PN::BaseString& output) {
	if (! m_in_use)
		return;

	dSP;

    ENTER;
    SAVETMPS;

	PUSHMARK(SP);
	XPUSHs(m_perl_obj);
	XPUSHs(newSVpv(script, 0));	// length of 0 means Perl will calculate
	PUTBACK;
	 
	int count = call_method("Eval", G_SCALAR);
	SPAGAIN;
	
	if (SvTRUE(ERRSV)) {
		STRLEN n_a;
		alert("Error calling Perl version of Eval: %s\n", SvPV(ERRSV,n_a));
		POPs;
	}
	else if (count == 1) {
		SV* retval = POPs;
		sv_catpvn(retval, "\0", 1);	// make sure it ends with a null
		output = SvPV_nolen(retval);
	}
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return;
}

void PerlScriptRunner::Exec(const char* function, const char* param, int flags, PN::BaseString& output) {
	if (! m_in_use)
		return;

	dSP;

    ENTER;
    SAVETMPS;

	PUSHMARK(SP);
	XPUSHs(m_perl_obj);
	XPUSHs(sv_2mortal(newSVpv(function, 0)));	// length of 0 means Perl will calculate
	XPUSHs(sv_2mortal(newSVpv(param, 0)));	// length of 0 means Perl will calculate
	XPUSHs(sv_2mortal(newSViv(flags)));
	PUTBACK;
	 
	int count = call_method("Exec", G_EVAL|G_SCALAR);
	SPAGAIN;
	
	if (SvTRUE(ERRSV)) {
		STRLEN n_a;
		alert("Error calling Perl version of Exec: %s\n", SvPV(ERRSV,n_a));
		POPs;
	}
	else if (count == 1) {
		SV* retval = POPs;
		sv_catpvn(retval, "\0", 1);	// make sure it ends with a null
		output = SvPV_nolen(retval);
	}
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return;
}

/*
 * PerlScriptTracker
 */

void PerlScriptRunner::SetId(const char* id) {
	int len = strlen(id);
	m_id = (const char*)malloc(len);
	strcpy((char*)m_id, id);
}

const char* PerlScriptRunner::Id() {
	return m_id;
}

PerlScriptTracker::PerlScriptTracker() {}

PerlScriptTracker::~PerlScriptTracker() {
	for (int i = 0; i < m_tracked_refs.size(); i++) {
		free((void*)m_tracked_refs[i]);
	}
}

bool PerlScriptTracker::Add(const char* scriptref) {
	char* newref = Fetch(scriptref);
	if (newref == NULL) {
		int len = strlen(scriptref);
		newref = (char*)malloc(len);
		strcpy(newref, scriptref);
		m_tracked_refs.push_back(newref);
		return true;
	}
	else
		return false;
}

char* PerlScriptTracker::Fetch(const char* scriptref) {
	for (int i = 0; i < m_tracked_refs.size(); i++) {
		if (strcmp(m_tracked_refs[i], scriptref) == 0)
			return m_tracked_refs[i];
	}
	return NULL;
}
